#include "l_list.h"

ll_node *
ll_node_create(elem_t e)
{
	ll_node * node = malloc(sizeof(ll_node));
	node->data = e;
	node->next = 0;
	return node;
}

void
ll_node_release(ll_node * node)
{
	free(node);
}

l_list
l_list_clone(const_l_list l)
{
	ll_node head;
	ll_node * node = &head;

	while (l) {
		node->next = ll_node_create(l->data);
		l = l->next;
		node = node->next;
	}

	return head.next;
}

void
l_list_release(l_list l)
{
	ll_node * node = 0;
	while (l) {
		node = l;
		l = l->next;
		ll_node_release(node);
	}
}

size_t
l_list_len(const_l_list l)
{
	size_t len = 0;
	while (l) {
		l = l->next;
		++len;
	}

	return len;
}

l_list
l_list_append(l_list * l, elem_t * p, size_t len)
{
	if (!len) {
		return *l;
	}

	if (!*l) {
		*l = ll_node_create(*p++);
		--len;
	}

	ll_node * node = *l;
	for (; node->next; node = node->next) {}

	for (; len; --len) {
		node->next = ll_node_create(*p++);
		node = node->next;
	}

	return *l;
}

void
l_list_display(const_l_list l)
{
	printf(" | ");
	while (l) {
		printf(" --> %d ", l->data);
		l = l->next;
	}
	printf("\n");
}

int
l_list_get(const_l_list l, index_t i, elem_t * e)
{
	for (index_t ii = 0; ii < i && l; ++ii, l = l->next) {}
	return l ? (*e = l->data, 0) : -1;
}

index_t
l_list_locate(const_l_list l, elem_t e)
{
	for (index_t i = 0; l; ++i, l = l->next) {
		if (l->data == e) {
			return i;
		}
	}

	return -1;
}

ll_iterator
l_list_insert(ll_iterator it, elem_t e)
{
	ll_node * node = ll_node_create(it->data);
	node->next = it->next;
	it->next = node;
	it->data =e;

	return it;
}

ll_iterator
l_list_delete(ll_iterator prev, elem_t * e)
{
	ll_node * node = prev->next;

	if (node) {
		*e = node->data;
		prev->next = node->next;
		ll_node_release(node);
		return prev->next;
	}
	else {
		return 0;
	}
}

l_list
l_list_sort(l_list * lp)
{
	ll_node head;
	ll_node * l = *lp;
	ll_node * node = 0;
	while (l) {
		node = l;
		l = l->next;

		ll_iterator it = &head;
		for (; it->next && node->data < it->next->data; it = it->next) {}
		node->next = it->next;
		it->next = node;
	}

	*lp = head.next;
	return head.next;
}

l_list
l_list_reverse(l_list * lp)
{
	ll_node * rl = 0;
	ll_node * l = *lp;
	ll_node * node = 0;

	while (l) {
		node = l;
		l = l->next;
		node->next = rl;
		rl = node;
	}

	*lp = rl;

	return rl;
}

